//888888888888888888888888888888888888888888888888888888888888888888888888888888888888888
//
//	File		 :	FormattedOutput.cpp
//	Contents	 :	Source file for class CRTFFormattedOutput
//	Creation Date:	22/12/1999
//	Last Modified:	23/12/1999	lg
//	tabs width	 :	every 4 characters
//
//888888888888888888888888888888888888888888888888888888888888888888888888888888888888888


#include "rtfformattedoutput.h"
#include <algorithm>
#include <iostream>
#include <cassert>
#include "../components/stlhelper.h"
using std::cerr;

//_______________________________________________________________________________________
//
//	StreamQueuedText()
//
//		Streams the accumulated text to the stream in the current format
//			using the RTF conventions
//		This version assumes that most of the text is in the default format and thus does
//			not support nesting of format tags. If this assumption is not true, a more
//			efficient stream might be possible
//		Last modified: lg 1/1/20100
//
//_______________________________________________________________________________________
void CRTFFormattedOutput::StreamQueuedText()
{
	// must call BeginHeader before add text etc.
	assert(IsInProgress());

	// check that something is in the queue
	if (!GetQueuedText().length())
		return;

	// formatting attributes are the same as default
	if (CurrentFormat == 0)
	{
		// put the text from the queue into the rtf stream
		StreamText(GetQueuedText());
		return;
	}


	std::string formatTxt;

	char buf[20];

	// background colour as one-based indices into the colour table
	assert(CurrentFormat < BackColourIndices.size());
	unsigned newCol = BackColourIndices[CurrentFormat];
	if (ColourTable[newCol] != ColourTable[BackColourIndices[0]])
	{
		sprintf(buf, "\\chcbpat%d", newCol+1);	
		formatTxt += buf;
	}

	// text colour as one-based indices into the colour table
	assert(CurrentFormat < TextColourIndices.size());
	newCol = TextColourIndices[CurrentFormat];
	if (ColourTable[newCol] != ColourTable[TextColourIndices[0]])
	{
		sprintf(buf, "\\cf%d", newCol+1);	
		formatTxt += buf;
	}

	// bold and italic
	if (GetFormat(CurrentFormat).Bold != GetFormat(0).Bold)
		formatTxt += GetFormat(CurrentFormat).Bold ? "\\b" : "\\b0";

	if (GetFormat(CurrentFormat).Italic != GetFormat(0).Italic)
		formatTxt += GetFormat(CurrentFormat).Italic ? "\\i" : "\\i0";

	// place the text and any formatting into the rtf stream
	if (formatTxt.empty())
		StreamText(GetQueuedText());
	else
	{
		StreamText('{');
		formatTxt += ' ' + GetQueuedText();
		formatTxt += '}';
		StreamText(formatTxt);
	}
}

//_______________________________________________________________________________________
//
//	AddNewLine()
//
//		Add new paragraph mark. Word does not imbed the paragraph mark in the middle of
//			the text. Can look into doing that.
//		Last modified: lg 23/12/1999
//
//_______________________________________________________________________________________
void CRTFFormattedOutput::AddNewLine()
{
	// must call BeginHeader before add text etc.
	assert(IsInProgress());
	StreamQueuedText();
	ClearQueuedText();
	StreamText("{\\par}");
}

void CRTFFormattedOutput::AddNewLineAndHalf()
{
	// must call BeginHeader before add text etc.
	assert(IsInProgress());
	StreamQueuedText();
	ClearQueuedText();

	// in 1/10 point sizes
	char buf[20];
	sprintf(buf, "{\\sa%d\\par}", GetTextSize());	
	StreamText(buf);
}

void CRTFFormattedOutput::AddDoubleNewLines()
{
	AddNewLine();
	AddNewLine();
}


//_______________________________________________________________________________________
//
//	DoBeginHeader()
//
//		Writes the RTF header and a table of all the colours which will be used.
//		The actual colours specified will be indices looked up from this table.
//		Last modified: lg 23/12/1999
//
//_______________________________________________________________________________________

template<class InputIterator, class T>
unsigned index_in_vector(InputIterator first, InputIterator last, T val)
{
	return std::find(first, last, val) - first;
}


template< class Container, class T>
inline unsigned index_in_vector(Container& c, T val)
{
	return index_in_vector(c.begin(),c.end(), val);
}


void CRTFFormattedOutput::DoBeginHeader()
{
	char buf[64];
	
	TextColourIndices.clear();
	BackColourIndices.clear();
	ColourTable.clear();
	ClearStream();
	
	StreamText("{\\rtf1\\ansi{\\colortbl;");
	
	// create a colour table of all the colours used
	ColourTable.clear();
	for (unsigned i = 0; i < GetFormatsCount(); ++i)
	{
		ColourTable.push_back(GetFormat(i).TextColour);
		ColourTable.push_back(GetFormat(i).BackColour);
	}
	
	// remove duplicate colours
	std::sort(ColourTable.begin(), ColourTable.end());
	ColourTable.erase(std::unique(ColourTable.begin(), ColourTable.end()), ColourTable.end());
	
	
	// map format indices into this table of colours
	for (unsigned i = 0; i < GetFormatsCount(); ++i)
	{
		assert(includes(ColourTable, GetFormat(i).TextColour));
		TextColourIndices.push_back(index_in_vector(ColourTable, GetFormat(i).TextColour));
		assert(includes(ColourTable, GetFormat(i).BackColour));
		BackColourIndices.push_back(index_in_vector(ColourTable, GetFormat(i).BackColour));
	}
	

	// write colour table to stream
	for (unsigned i = 0; i < ColourTable.size(); ++i)
	{
		sprintf(buf, "\\red%d\\green%d\\blue%d;",
						ColourTable[i].red(),
						ColourTable[i].green(),
						ColourTable[i].blue());	
		StreamText(buf);
	}

	// write the default font name to the rich text stream
	StreamText("}\\deff0{\\fonttbl{\\f0\\fmodern\\fprq1 ");
	StreamText(GetTextFont());
	StreamText(";}}");

	// write defaults format to the rich text stream
	sprintf(buf, "\\fs%d\\chcbpat%d\\cf%d\\b%s\\i%s ",
			GetTextSize() / 5,				//	textsize in half point sizes
			BackColourIndices[0]+1,			//	back colour
			TextColourIndices[0]+1,			//	font colour
			GetFormat(0).Bold	? "":"0",	//	font bold
			GetFormat(0).Italic	? "":"0"	//	font italic
			);
	StreamText(buf);

}


//_______________________________________________________________________________________
//
//	DoEndFooter()
//
//		Closes off the RTF stream
//		Last modified: lg 23/12/1999
//
//_______________________________________________________________________________________
void CRTFFormattedOutput::DoEndFooter()
{
	StreamText('}');
}


const std::string& CRTFFormattedOutput::GetStreamedText(unsigned)
{
	return FormattedStream;
}

#ifdef _MFC_VER	// mfc specific code to follow
//_______________________________________________________________________________________
//
//	GetClipboardFormat()
//
//		returns the Windows RTF clipboard format descriptor unsigned
//		Last modified: lg 23/12/1999
//
//_______________________________________________________________________________________
const std::string& CRTFFormattedOutput::GetClipStreamedText(unsigned)
{
	return FormattedStream;
}

unsigned CRTFFormattedOutput::GetClipboardFormat(unsigned)
{
	return RegisterClipboardFormat(CF_RTF);
//	return CF_TEXT;
}

#endif

unsigned CRTFFormattedOutput::GetFileFormatCounts()
{
	// only supports one format: RTF
	return 1;
}

